package org.NooLab.glue.components;

import java.util.Observer;

import org.NooLab.glue.MessageBoard;
import org.NooLab.glue.msgframe.XRegistration;
import org.NooLab.glue.net.ComBox;
import org.NooLab.glue.net.ComBoxIntf;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.net.GUID;
import org.NooLab.utilities.timing.Delay;


/**
 * 
 * we need a dedicated object for sending to be thread-safe;
 * any instance wishing to send has to instantiate it
 * 
 * TODO: should allow transport protocols that are specific for a particular xreg !
 * 
 */

public class SenderWrap implements Runnable{

	MessageBoard msgboard;
	ComBoxIntf comBox;
	Observer swObserver = null;
	int lastState=0;
	boolean waitForPerformCompletion = false, completed;
	
	String thrdSurname="";
	String preparedMsg;
	int port;
	int result = -1, startedState=0;
	
	Thread sndwrapThrd;
	PrintLog out;
	
	public SenderWrap(MessageBoard mb) {
		msgboard = mb;
		comBox = msgboard.getComBox();
		 
		initProcess();
	}
	
	public SenderWrap(MessageBoard mb, String thrdMarker) {
		msgboard = mb;
		comBox = msgboard.getComBox();
		 
		thrdSurname = "-"+thrdMarker ;
		initProcess();
	}
	
	public SenderWrap(ComBoxIntf combox) {
		comBox = combox;
		initProcess();
	}
	private void initProcess(){
		sndwrapThrd = new Thread(this, "sndwrapThrd"+thrdSurname) ;
		out = comBox.getFactory().out;
	}
	
	public void setObserver( Observer observer){
		// mbf.comBoxFactory.setObserver( msgboard ) ;
		swObserver = observer ; 
	}

	// use this in all cases, where  messages could be long,such that collisions are to be expected
	// test whether collisions occur on sockets... !!??
	public int sendingMessage(String preparedMsg, XRegistration xreg) {
		int r=-1;
		
		try{
		
			r = sendingMessage(preparedMsg, xreg.getActiveport() ) ;
	
		}catch(Exception e){
			
		}
		
		return r;
	}
	
	// use this for short messages, where no collisions are to be expected
	public int sendingMessage( String preparedmsg, int port ){
		
		// globalize to this object
		preparedMsg = preparedmsg;
		this.port = port ;
		
		// ensure the thread is NOT running (for whatever reason...)
		if ((sndwrapThrd !=  null) && (startedState>0)){
			try{
				sndwrapThrd.join(5);
			}catch(Exception e){}
			
			out.delay(20);
			sndwrapThrd = null ;
			sndwrapThrd = new Thread(this, "sndwrapThrd") ;
		}
		
		// start it: it will take the preparedMsg and send it through the combox
		sndwrapThrd.start();
		
		result = 0;
		
		// waiting is required: waiting needs to be set as "fulfilled" through 
		// interfaced method setWaitForperformCompletion()...
		if (waitForPerformCompletion){
			int z=0;
			while ((completed==false) && (z<200)){
				out.delay(10); z++;
			}
		}
		try{
			sndwrapThrd.interrupt();
		}catch(Exception e){}
		
		// important: release the object here !
		sndwrapThrd=null;
		
		return result;
	}
	
	private void perform(){
		
		
		String sendingUUID;
		DataSenderIntf sender = null;

		try{
			completed=false;
			
			if (preparedMsg.length()>0){
				sender = comBox.createSender(port, 7111, "MB");

				if (swObserver!=null){
					comBox.getFactory().setObserver(swObserver) ; // zone of overlap :)
				}
				
				sendingUUID = GUID.randomvalue() ;
				// this will be kept only for some time, or for the last 1000 sends
				
				sender.send( preparedMsg, sendingUUID ); // implicit "objectification"

				
				lastState = sender.getLastState( sendingUUID );
				
				if (lastState != 0){
					// the state comes directly from the respective sender, e.g. the tcp-client...
					// that is, the error state is related to the wire connectivity !
					comBox.getFactory().out.printErr(3, "Error in contacting the 'wires' in sending, code = "+lastState);
					 
				}
				result = lastState;
			}else{
				result = 3 ;
			}
			
		}catch(Exception e){
			result = -17;
		}
		completed=true;
		
		try{
			sndwrapThrd.join();
		}catch(Exception e){}
		
		
		if (sender!=null){
			sender.release();
		}
		sender = null;
	}

	@Override
	public void run() {
		startedState = 1;
		perform();
		startedState = -1;
	}

	public void setWaitForPerformCompletion(boolean waitForPerformCompletion) {
		this.waitForPerformCompletion = waitForPerformCompletion;
	}


}
